#![allow(dead_code)]

use mlua::{Lua, Result};
use std::collections::HashMap;
use lazy_static::lazy_static;
use hyper::{Body,Client};
use hyper_tls::HttpsConnector;
use hyper::client::HttpConnector;
use hyper::http::{Response};
use crate::models::http::model_request::HttpRequest;
use crate::util::util::return_error;
use super::model_other::ErrorTimeout;
use crate::models::http::model_response::HttpResponse;

lazy_static! {
    // pub static ref http_client:Client<HttpConnector> = Client::new();
    pub static ref HTTPS_CLIENT:Client<HttpsConnector<HttpConnector>> = Client::builder().build::<_, hyper::Body>(HttpsConnector::new());
}

pub async fn http_do_table(_lua:&Lua, lua_request: HttpRequest) -> Result<HashMap<String,String>>{
    let mut table = HashMap::new();
    let request = match lua_request.to_request(){
        Ok(o)=>o,
        Err(e)=>{
            return return_error(table,e)
        }
    };
    let resp = match HTTPS_CLIENT.request(request).await {
        Err(e)=>{
            return return_error(table,e.to_string())
        }
        Ok(o)=>o,
    };
    table.insert("status".to_string(), resp.status().as_u16().to_string());
    for (key,value) in resp.headers().iter() {
        table.insert(key.to_string(), value.to_str().unwrap().to_string());
    }
    let body = hyper::body::to_bytes(resp.into_body()).await.unwrap();
    unsafe {
        table.insert("body".to_string(),String::from_utf8_unchecked(body.to_vec()));
    }
    return Ok(table)
}

pub async fn http_do(_lua:&Lua, lua_request: HttpRequest) -> Result<HttpResponse>{
    let request = match lua_request.to_request(){
        Ok(o)=>o,
        Err(e)=>{
            return Ok(HttpResponse::error(e))
        }
    };
    let timeout = tokio::time::sleep(lua_request.get_timeout());
    let request_do = HTTPS_CLIENT.request(request);
    let res:std::result::Result<Response<Body>,String> = tokio::select! {
        res = request_do => {
            match res {
            Ok(o)=>Ok(o),
            Err(e)=>Err(e.to_string())
            }
        },
        _ = timeout => {
            Err(ErrorTimeout.to_string())
        },
    };
    let resp = match res {
        Err(e)=>{
           return Ok(HttpResponse::error(e))
        }
        Ok(o)=>o,
    };
    Ok(HttpResponse::new(resp))
}

